package org.example.btchat.server;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.example.btchat.BTChatInterface;
import org.example.btchat.MainActivity;
import org.example.btchat.Message;
import org.example.btchat.R;

import org.example.btchat.BTChat;
import org.example.btchat.server.AcceptThread;

import android.app.Activity;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;

public class ServerService extends Service implements BTChatInterface
{
	public class LocalBinder extends Binder
	{
		public ServerService getService()
		{
			return ServerService.this;
		}
	}
	
	private List<Connection> connections = new ArrayList<Connection>();
	private AcceptThread acceptThread;
	private MainActivity activity = null;
	private BluetoothAdapter adapter;
	private ArrayList<Message> messages = new ArrayList<Message>();
	private BluetoothServerSocket server;
	
	@Override
	public String getName()
	{
		return adapter.getName();
	}
	
	public void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		if(requestCode == BTChat.REQUEST_ENABLE_BT)
		{
			if(resultCode == Activity.RESULT_OK)
			{
				try
				{
					startServer();
				}
				catch(IOException e)
				{
					stopSelf();
				}
				return;
			}
			else
			{
				Toast.makeText(this, getString(R.string.msg_bluetooth_not_active), Toast.LENGTH_LONG)
					.show();
				stopSelf();
				return;
			}
		}
	}
	
	@Override
	public IBinder onBind(Intent intent)
	{
		return new LocalBinder();
	}
	
	public void onMessageSent(final Message msg)
	{
		for(Connection connection : this.connections)
		{
			try
			{
				connection.send(msg);
			}
			catch(IOException e)
			{
				Toast.makeText(
					this,
					getString(R.string.msg_lost_connection, connection.socket.getRemoteDevice().getName()),
					Toast.LENGTH_SHORT).show();
				connection.close();
				this.connections.remove(connection);
			}
		}
		
		messages.add(msg);
		
		activity.runOnUiThread(new Runnable()
		{
			@Override
			public void run()
			{
				activity.onMessageReceive(msg);
			}
		});
	}
	
	public void onSocketConnected(BluetoothSocket socket)
	{
		try
		{
			this.connections.add(new Connection(this, socket));
		}
		catch(IOException e)
		{
			return;
		}
	}
	
	@Override
	public void sendMessage(final Message msg)
	{
		for(Connection connection : this.connections)
		{
			try
			{
				connection.output.write(msg.toString().getBytes());
			}
			catch(IOException e)
			{
				Toast.makeText(
					this,
					getString(R.string.msg_lost_connection, connection.socket.getRemoteDevice().getName()),
					Toast.LENGTH_SHORT).show();
				connection.close();
				this.connections.remove(connection);
			}
		}
		
		messages.add(msg);
		
		activity.runOnUiThread(new Runnable()
		{
			@Override
			public void run()
			{
				activity.onMessageReceive(msg);
			}
		});
	}
	
	public void setActivity(MainActivity activity)
	{
		this.activity = activity;
	}
	
	public void start() throws Exception
	{
		adapter = BluetoothAdapter.getDefaultAdapter();
		
		if(adapter == null)
		{
			Toast.makeText(this, getString(R.string.msg_no_bluetooth), Toast.LENGTH_LONG).show();
			stopSelf();
			return;
		}
		
		if(adapter.isEnabled())
		{
			startServer();
		}
		else
		{
			startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE),
				BTChat.REQUEST_ENABLE_BT);
		}
	}
	
	private void startActivityForResult(Intent intent, int requestCode) throws Exception
	{
		if(activity != null)
			activity.startActivityForResult(intent, requestCode);
		else
			throw new Exception("No activity set to interact!");
	}

	private void startServer() throws IOException
	{
		try
		{
			server = adapter.listenUsingRfcommWithServiceRecord(BTChat.MY_NAME, BTChat.MY_UUID);
		}
		catch(IOException e)
		{
			Toast.makeText(this, getString(R.string.msg_no_connection), Toast.LENGTH_LONG).show();
			throw e;
		}
		
		acceptThread = new AcceptThread(server, this);
		acceptThread.start();
	}
}
